from django.db import models
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import Permission

from .validators import validate_permstr, validate_username, validate_screen_width, validate_boardname, validate_latinchar, validate_showname
from . import auth_module
import markdown

#ForumUser by author @ 2014/5/29
class ForumUser(auth_module.ForumUser):
    class Meta:
        verbose_name = u'user'
        verbose_name_plural = u'users'

class Message(models.Model):
    """
    Messages for users.
    """

    name = models.CharField(max_length=20, unique=True, validators=[validate_latinchar])

    content = models.TextField()

    post_time = models.DateTimeField("Created date", auto_now_add=True)
    last_edited = models.DateTimeField("Last edited", auto_now=True)

    def __unicode__(self):
        return self.name

class CommonPart(models.Model):
    """
    Common parts for Topic and Push
    """

    author = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.SET_NULL)

    post_time = models.DateTimeField("Created date", auto_now_add=True)
    last_edited = models.DateTimeField("Last edited", auto_now=True)

    post_ip = models.IPAddressField("Author's IP address", default='0.0.0.0')

    class Meta:
        abstract = True

class Topic(CommonPart):

    title = models.CharField(max_length=254, validators=[validate_screen_width(56)])

    content = models.TextField()
    output_content = models.TextField()

    #father_node is the ID of Topic to which this topic(or push) belong to.
    father_node = models.ForeignKey('self', blank=True, null=True, on_delete=models.SET_NULL)

    #tree_node is a unique number shared by every Topic and its replies.
    #With this value, Replies belong to a same Topic can
    #still be identified even their Topic is delete.
    tree_node = models.IntegerField(default=None)

    board = models.ForeignKey('Board', blank=True, null=True, on_delete=models.SET_NULL)

    attachments = models.ManyToManyField('Attachment')

    def save(self, *args, **kwargs):
        self.output_content = markdown.markdown(self.content, output_format='html5', safe_mode='escape', lazy_ol=True)

        if self.tree_node == None:
            #In case there is no existing primary key
            #Set tree_node = 0 for the first Topic.
            try:
                self.tree_node = Topic.objects.latest('pk').id
            except Topic.DoesNotExist:
                self.tree_node = 0
            super(Topic, self).save(*args, **kwargs)
        else:
            super(Topic, self).save(*args, **kwargs)

    def __unicode__(self):
        return self.title

class Push(CommonPart):
    """
    A Push is an one-line comment attached to a Topic
    It is a special kind of Reply without a title in nature
    """
    #Push's length is limited to 35 full-width characters
    #or 70 half-width characters.
    content = models.CharField(max_length=254, validators=[validate_screen_width(70)])

    #Pushes are stored in a different table from Topic/Reply
    father_node = models.ForeignKey('Topic')

    #attitude       effect to Topic/Reply
    #  None                 nothing
    #   1                 like += 1
    #   0              dislike += 1
    attitude = models.IntegerField(blank=True, default=None, null=True)

    def __unicode__(self):
        return self.content

class Board(models.Model):
    """
    Board stores all attributes of boards.
    """
    #Boardname length, between 3 chars to 20 chars.
    name = models.CharField(max_length=20, unique=True, validators=[validate_boardname])

    #Could be Chinese characters.
    showname = models.CharField(max_length=30, blank=True, validators=[validate_showname])

    discription = models.CharField(max_length=254, blank=True)

    #Access restriction
    restrict = models.IntegerField(default=0)

    #time when this board created
    created_time = models.DateTimeField(auto_now_add=True)

    #A board MUST be belong to a category
    category = models.ForeignKey('BoardCategory', null=True, blank=True, )

    #Corresponding access permission(Some board can only be accessed by specified users)
    co_permission = models.ForeignKey(Permission, related_name='+')

    #Permission for managing this board
    admin_permission = models.ForeignKey(Permission, related_name='+')

    #Explanation for permissions:
    #    _         _          _                 _                           _               (possible values: 0, 1)
    # access  reply/push  post topic  delete(not posted by self)  edit(not posted by self)
    anonymous_perm = models.CharField(max_length=5, default='10000', validators=[validate_permstr])
    user_perm = models.CharField(max_length=5, default='11100', validators=[validate_permstr])
    admin_perm = models.CharField(max_length=5, default='11110', validators=[validate_permstr])

    def save(self, *args, **kwargs):
        #Generate a default showname
        if not self.showname:
            self.showname = self.name

        #Generate initial permission for this board
        content_type = ContentType.objects.get_for_model(Board)
        perm_name = self.name + '_access'
        perm_name_admin = self.name + '_admin'

        if not Permission.objects.filter(codename=perm_name).exists():
            if self.id:
                self.co_permission.codename = perm_name
                self.co_permission.save()
            else:
                self.co_permission = Permission.objects.create(
                        codename=perm_name,
                        name='Can access this board',
                        content_type=content_type
                        )

        if not Permission.objects.filter(codename=perm_name_admin).exists():
            if self.id:
                self.admin_permission.codename = perm_name_admin
                self.admin_permission.save()
            else:
                self.admin_permission = Permission.objects.create(
                        codename=perm_name_admin,
                        name='Can manage this board',
                        content_type=content_type
                        )

        super(Board, self).save(*args, **kwargs)

    def __unicode__(self):
        return self.name

class BoardCategory(models.Model):
    """
    Categories of boards
    """
    #Categoryname length, between 3 chars to 20 chars.
    #Must be latin characters
    name = models.CharField(max_length=20, unique=True, validators=[validate_boardname])

    #Could be Chinese characters.
    showname = models.CharField(max_length=30, blank=True, validators=[validate_showname])

    discription = models.CharField(max_length=254)

    def save(self, *args, **kwargs):
        #Generate a default showname
        if not self.showname:
            self.showname = self.name

        super(BoardCategory, self).save(*args, **kwargs)

    def __unicode__(self):
        return self.name

class Attachment(CommonPart):
    owner = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.SET_NULL)
    discription = models.CharField(max_length=254)
    file = models.FileField(upload_to='lcforum/%Y%m%d')

    def save(self, *args, **kwargs):
        super(BoardCategory, self).save(*args, **kwargs)
